
//集合是由一组无序且唯一（即不能重复）的项组成的

// 并集：对于给定的两个集合，返回一个包含两个集合中所有元素的新集合
// 交集：对于给定的两个集合，返回一个包含两个集合中共有元素的新集合
// 差集：对于给定的两个集合，返回一个包含所有存在于第一个集合且不存在于第二个集合的元素的新集合
// 子集：验证一个给定集合是否是另一集合的子集

//没有副作用的方法和函数被称为纯函数。纯函数不会修改当前的实例或参数，只会生成一个新的结果。这在函数式编程中是非常重要的概念

export class Set<T> {

    private _items: any;
    public constructor() {
        this._items = {};
    }

    public add(ele: T) {
        if (!this.has(ele)) {
            this._items[ele] = ele;
            return true;
        }
        return false;
    }

    public delete(ele: T) {
        if (this.has(ele)) {
            delete this._items[ele];
            return true;
        }
        return false;
    }

    public has(ele: any) {
        return Object.prototype.hasOwnProperty.call(this._items, ele);
    }

    public clear() {
        this._items = {};
    }

    public values(): T[] {
        let values = [];
        for (let key in this._items) {
            if (this._items.hasOwnProperty(key)) {
                values.push(this._items[key]);
            }
        }
        return values;
    }

    //并集
    public union(otherSet: Set<T>) {
        const unionSet = new Set();
        this.values().forEach(ele => { unionSet.add(ele) });
        otherSet.values().forEach(ele => { unionSet.add(ele) });
        return unionSet;
    }

    //交集
    public intersection(otherSet: Set<T>) {
        const intersectionSet = new Set()
        const values = this.values();
        const otherValues = otherSet.values();

        let bigger = values.length > otherValues.length ? values : otherValues;
        let smaller = bigger == values ? otherValues : values;

        smaller.forEach(ele => {
            if (bigger.indexOf(ele) != -1) {
                intersectionSet.add(ele);
            }
        })

        return intersectionSet;
    }

    //差集
    public difference(otherSet: Set<T>) {
        const differenceSet = new Set<T>();
        this.values().forEach(ele => {
            if (!otherSet.has(ele)) {
                differenceSet.add(ele);
            }
        });
        return differenceSet;
    }

    //子集
    public isSubsetof(otherSet: Set<T>) {
        if (this.length > otherSet.length) {
            return false;
        }
        let isSubset = true;
        this.values().every(ele => {
            if (!otherSet.has(ele)) {
                isSubset = false;
                return false;
            }
            return true;
        });
        return isSubset;
    }

    public get length() {
        return Object.keys(this._items).length;
    }


}